#include "main.h"


#include <exception>
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <sstream>


#include "TreeView.h"

using namespace std;


// Command line:
//
//       rats [<fileroot>] [-t]
//
void read_command(int argc, char* argv[], map<string,string>& args)
{
	args["fileroot"] = "default";

	for(int i=1; i < argc; i++)
	{
		if (argv[i][0] == '-') args[argv[i]] = "yes";
		else args["fileroot"] = argv[i]; // a miracle that it works !!!
	}
}

TreeView solver(istream& tree, istream& costbenefit, bool transformTree)
{
        // Build the structure of the tree:

        TreeView tv(tree);
        tv.bottom_up(&TreeView::resolve_monofurcation);
        tv.bottom_up(&TreeView::resolve_multifurcation);
        
        tv.get_rev().top_down(&TreeView::calc_representation);
        
        // Set the cost-benefit information:

        tv.set_cost_benefits(costbenefit);
        tv.get_rev().reset_pT();


        //Transform the tree if necessary
        if (transformTree)
        {
                tv.transform_lengths_and_probs();
        }
        // Do the calculations:

        // -----------------------------------
        tv.bottom_up(&TreeView::calc_eplists);
        // -----------------------------------

        if (!dNAP)  // TreeView::dNAP?
        {
                // --------------------------------------------
                tv.get_rev().top_down(&TreeView::calc_eplists);
                // --------------------------------------------
        }
        return tv;

}

char* perl_main(char tree[], char costbenefit[] )
{

    string treestring(tree);
    string cbstring(costbenefit);

    stringbuf tree_buf(treestring, ios::in);
    istream tree_istream(&tree_buf);

    stringbuf cb_buf(cbstring, ios::in);
    istream cb_istream(&cb_buf);

    //Call the real main function
    TreeView tv = solver(tree_istream,cb_istream,1);

    //Output

    //Using a stream so can keep modifications to Fabio's code to a minimum
    int length;
    char * buffer;
    stringbuf out_buf( ios::in | ios::out);
    iostream out_stream(&out_buf);

    //Print the full table to the stream
    tv.print_rPD_solutions_as_table(out_stream);
    //Get the full string
    out_stream.seekg (0, ios::end);
    length = out_stream.tellg();
    out_stream.seekg (0, ios::beg);
    // allocate memory:
    buffer = new char [length+1];

    // read data as a block:
    //out_stream.read (buffer,length);
    out_stream.getline(buffer,length+1,'\0');

    return buffer;

}

int main(int argc, char* argv[])
{
	try 
	{
		map<string,string> args; // General way of storing progr. arguments
		read_command(argc, argv, args);

                string treefilename (args["fileroot"] + ".tree");
                string cbfilename (args["fileroot"] + ".cb");

                //Create ifstreams out of the filenames
                ifstream tree (treefilename.c_str() , ifstream::in );
                if (!tree) throw string("cannot open " + treefilename);
                ifstream cb (cbfilename.c_str() , ifstream::in );
                if (!cb) throw string("cannot open " + cbfilename);

                //Call the real main function
                TreeView tv = solver(tree,cb,args["-t"] == "yes");

                //Output

                //Print the transformed tree
                if (args["-t"] == "yes")
                {
                        ofstream newtree((args["fileroot"] + ".newtree").c_str());
                        if (newtree)
                                tv.print_tree(newtree, true);
                }

                tv.print_solution_for_rooted_PD(C);

                ofstream outfile((args["fileroot"] + ".out").c_str());
                if (outfile) 
                        tv.print_solution_for_rooted_PD(C, outfile);

                ofstream details((args["fileroot"] + ".details").c_str());
                if (details) 
                        tv.print_rPD_solutions_as_table(details);
                        // tv.print_all_solutions_for_rooted_PD(details);
        
                if (!dNAP)  // TreeView::dNAP?
                {
        
                        tv.print_solution_for_unrooted_PD(C);
                        if (outfile) 
                                tv.print_solution_for_unrooted_PD(C, outfile);
                        if (details) 
                                tv.print_uPD_solutions_as_table(details);
                                // tv.print_all_solutions_for_unrooted_PD(details);
                }


	} 
	catch (string& s) { cout << "\nError: " << s << endl; return 1; }
	catch (exception& e) { cout << e.what() << endl; return 1; }

	return 0;
}

char* test(int a)
{
    int length;
    char * buffer;

    stringbuf out_buf( ios::in | ios::out);
    iostream test(&out_buf);

    test << "thisisatest\n";
    test.seekg (0, ios::end);
    length = test.tellg();
    test.seekg (0, ios::beg);
    // allocate memory:
    buffer = new char [length];

        // read data as a block:
    test.read (buffer,length);                


    return buffer;
}






